<?php

namespace App\Library\OperationLog;


use Illuminate\Support\Collection;

class OperationLog
{
    const TYPE_DEL    = 1;
    const TYPE_INSERT = 2;
    const TYPE_UPDATE = 3;

    const FIELD_STRING       = 1;
    const FIELD_ENUM         = 2;
    const FIELD_PUB_IMG      = 3;
    const FILED_PRI_IMG      = 4;
    const FIELD_TABLE_COLUMN = 5;

    public int         $type;
    public string      $title;
    public ?Collection $before = null;
    public ?Collection $after  = null;
    public Collection  $translate;

    const EXCEPT_FIELDS = ["id", "createdAt", "updatedAt", "createdByUid", "updatedByUid", "isDeleted"];

    public function __construct(
        int $type,
        string $title,
        $before = null,
        $after = null,
        array $translate = [],
        \Closure $closure = null
    ) {
        $this->type      = $type;
        $this->title     = $title;
        $this->before    = $before instanceof Collection ? $before : collect($before ?? []);
        $this->after     = $after instanceof Collection ? $after : collect($after ?? []);
        $this->translate = collect($translate);
    }

    public function generateLogContent()
    {
        switch ($this->type) {
            case self::TYPE_DEL:
                return $this->before->map(function ($before) {
                    return collect($before)->except(self::EXCEPT_FIELDS)->map(function ($v, $k) {
                        list($type, $desc, $before, $after) = $this->getFieldShow($k, $v, null);
                        return [
                            "type"   => $type,
                            "field"  => $k,
                            "before" => $before,
                            "after"  => $after,
                            "desc"   => $desc
                        ];
                    })->values();
                })->values()->toArray();
                break;
            case self::TYPE_INSERT:
                return $this->after->map(function ($after) {
                    return collect($after)->except(self::EXCEPT_FIELDS)->map(function ($v, $k) {
                        list($type, $desc, $before, $after) = $this->getFieldShow($k, null, $v);
                        return [
                            "type"   => $type,
                            "field"  => $k,
                            "before" => $before,
                            "after"  => $after,
                            "desc"   => $desc
                        ];
                    })->values();
                })->values()->toArray();
                break;
            case self::TYPE_UPDATE:
                break;
        }
    }


    /**
     * @param string $field
     * @param $before
     * @param $after
     * @return array|void
     */
    public function getFieldShow(string $field, $before, $after)
    {
        $translateConfig = attributeGet($this->translate, "{$field}", $field);
        if (is_string($translateConfig)) {
            return [OperationLog::FIELD_STRING, $translateConfig, $before, $after];
        }

        $type = attributeGet($translateConfig, "type", null);
        switch ($type) {
            case OperationLog::FIELD_STRING:
                return [
                    $type,
                    attributeGet($translateConfig, "desc", $field),
                    $before,
                    $after
                ];
                break;
            case OperationLog::FIELD_TABLE_COLUMN:
                $config = attributeGet($translateConfig, "config", null);
                if (count($config) == 3) {
                    list($tableName, $tableSearchColumn, $tableShowColumn) = $config;
                    return [
                        $type,
                        attributeGet($translateConfig, "desc", $field),
                        $before === null ? $before : attributeGet(
                            $tableName::query()->where($tableSearchColumn, $before)->first(),
                            $tableShowColumn,
                            $field
                        ),
                        $after === null ? $after : attributeGet(
                            $tableName::query()->where($tableSearchColumn, $after)->first(),
                            $tableShowColumn,
                            $field
                        ),
                    ];
                } else {
                    return [
                        $type,
                        attributeGet($translateConfig, "desc", $field),
                        $before,
                        $after
                    ];
                }
                break;
            case OperationLog::FIELD_ENUM:
                $config = attributeGet($translateConfig, "config", null);
                return [
                    $type,
                    attributeGet($translateConfig, "desc", $field),
                    attributeGet($config, $before, $field),
                    attributeGet($config, $after, $field)
                ];
                break;
        }

    }
}
